package cn.miju.dict.validate;

import cn.hutool.core.collection.CollUtil;
import cn.miju.dict.constant.DictConstant;
import com.google.common.collect.Sets;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <pre>
 * 验证字典参数值约束实
 * 使用方式：
 * 1、自定义字典有效值区间-配置values
 * 2、缓存字典有效值区间-配置key
 * </pre>
 *
 * @author zhuming
 * @version 1.0.0
 * @since 2023-04-24 16:40
 */
@Data
@RequiredArgsConstructor
public class DicValidator implements ConstraintValidator<Dict, Object> {
    private static final Log LOG = LoggerFactory.make(MethodHandles.lookup());
    private final StringRedisTemplate redisTemplate;
    /**
     * 有效值
     */
    private Set<String> effectValues;
    /**
     * 字典Key
     */
    private String key;

    @Override
    public void initialize(Dict dict) {
        if (StringUtils.isNotBlank(dict.values())) {
            this.effectValues = Arrays.stream(dict.values().split(",")).collect(Collectors.toSet());
        }
        this.key = dict.key();
    }

    /**
     * Implements the validation logic.
     * The state of {@code value} must not be altered.
     * <p>
     * This method can be accessed concurrently, thread-safety must be ensured
     * by the implementation.
     *
     * @param value   object to validate
     * @param context context in which the constraint is evaluated
     * @return {@code false} if {@code value} does not pass the constraint
     */
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (StringUtils.isBlank(key) && CollUtil.isEmpty(effectValues)) {
            LOG.error("DictValidator 字典key和自定义有效值区间不能同时为空");
            return false;
        }
        if (null == value || StringUtils.isBlank(String.valueOf(value))) {
            return true;
        }
        if (CollUtil.isEmpty(effectValues)) {
            String redisKey = DictConstant.Redis.DICT_VALIDATE_KEY + key;
            if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
                return true;
            }
            Set<String> members = redisTemplate.opsForSet().members(redisKey);
            if (CollUtil.isEmpty(members)) {
                LOG.error("DictValidator 未从缓存中读取到字典有效值");
                return false;
            }
            return members.contains(String.valueOf(value));
        }
        return effectValues.contains(String.valueOf(value));
    }
}
